package server.game.players;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import java.util.Queue;
import java.util.concurrent.Future;

import server.content.DupeDefender;
import server.content.SQL;
import server.content.skilling.PlayerSkill;
import server.content.skilling.fishing.MiracleFishing;
import server.content.skills.Prayer;
import org.apache.mina.common.IoSession;
import server.event.CycleEventHandler;
import server.Config;
import server.Server;
import server.game.items.ItemAssistant;

import server.game.players.combat.CombatAssistant;
import server.game.shops.ShopAssistant;
import core.net.HostList;
import core.net.Packet;
import core.net.StaticPacketBuilder;
import core.util.Misc;
import core.util.Stream;
import server.content.skills.*;
import server.content.skills.filling.Filling;
import server.content.skills.fm.MiracleFM;
import server.content.skills.mining.MMining;
  
import server.content.skills.misc.SkillConstants;
import server.content.skills.misc.SkillInterfaces;
import server.content.skills.misc.SmithingInterface;
import server.content.skills.thieving.Theiving;
import server.content.skills.wc.MiracleWC;
import server.event.EventManager;
import server.event.Event;
import server.event.EventContainer;
import server.content.abilities.BananaPicking;
import server.content.dungeons.BrimDungeon;
import server.content.quests.*;
import server.content.quests.misc.QuestConfig;
import server.content.randoms.RandomEvent;
import server.content.randoms.TreeSpirit;

public class Client extends Player {

	/*
	 * Yell options.
	 */
	public AntiBot antiBot = new AntiBot(this);
	public final int OFF = 1, ON = 0;
	public int eco_reset = 0;
	public int toggleYell = ON;
	public long lastHome;
	public byte buffer[] = null;
	public Stream inStream = null, outStream = null;
	private IoSession session;
	private ItemAssistant itemAssistant = new ItemAssistant(this);
	private ShopAssistant shopAssistant = new ShopAssistant(this);
	private TradeAndDuel tradeAndDuel = new TradeAndDuel(this);
	private PlayerAssistant playerAssistant = new PlayerAssistant(this);
	private CombatAssistant combatAssistant = new CombatAssistant(this);
	private ActionHandler actionHandler = new ActionHandler(this);
	private PlayerKilling playerKilling = new PlayerKilling(this);
	private DialogueHandler dialogueHandler = new DialogueHandler(this);
	private Queue<Packet> queuedPackets = new LinkedList<Packet>();
	public MiracleFishing fisha = new MiracleFishing(this, SkillConstants.FISHING);
	private Potions potions = new Potions(this);
	private Fishing fish = new Fishing(this);
	private PotionMixing potionMixing = new PotionMixing(this);
	private Food food = new Food(this);
	public DupeDefender dupeDefender = new DupeDefender(this);

	/*
	 * Dungeons.
	 */
	public BrimDungeon brimDung = new BrimDungeon(this);

	public int yellTimer = -1;
	public long fixMe = -1;

	private ActionAssistant2 actionAssistant2 = new ActionAssistant2(this);
	// private TutorialIsland tutorialIsland = new TutorialIsland(this);

	private SkillInterfaces skillInterfaces = new SkillInterfaces(this);

	public BananaPicking bananaPicking = new BananaPicking(this);
	public MMining mine = new MMining(this, SkillConstants.MINING);
	public Filling filling = new Filling(this);

	/**
	 * Quests
	 */
	public final Map<Integer, Integer> questStages = new HashMap<Integer, Integer>();
	public CooksAss cooksAss = new CooksAss(this,
			QuestConfig.COOKS_ASSISTANT.getQuestId());
	/**
	 * Skill instances
	 */
	private Slayer slayer = new Slayer(this);
	private Runecrafting runecrafting = new Runecrafting(this);
	public int gloryDeg = -1;
	public MiracleWC woodcutting = new MiracleWC(this);
	public MiracleFM firemaking = new MiracleFM(this);
	public MineEss mineEss = new MineEss(this);
	public Theiving theiving = new Theiving(this);
	public final List<PlayerSkill> playerSkills = new LinkedList<PlayerSkill>();

	public boolean hasRandom;
	public final List<RandomEvent> randoms = new LinkedList<RandomEvent>();
	public TreeSpirit treeSpirit = new TreeSpirit(this);

	private Agility agility = new Agility(this);
	// private Cooking cooking = new Cooking(this);
	private Crafting crafting = new Crafting(this);
	// private Fletching fletching = new Fletching(this);
	private Farming farming = new Farming(this);
	private Prayer prayer = new Prayer(this);
	private SmithingInterface smithInt = new SmithingInterface(this);
	private Smithing smith = new Smithing(this);
	private Magic magic = new Magic(this);
	private Herblore herblore = new Herblore(this);

	// private int somejunk;
	public int lowMemoryVersion = 0;
	public int timeOutCounter = 0;
	public int returnCode = 2;
	private Future<?> currentTask;
	public int currentRegion = 0;

	public Client(IoSession s, int _playerId) {
		super(_playerId);
		this.session = s;
		synchronized (this) {
			outStream = new Stream(new byte[Config.BUFFER_SIZE]);
			outStream.currentOffset = 0;

			inStream = new Stream(new byte[Config.BUFFER_SIZE]);
			inStream.currentOffset = 0;
			buffer = new byte[Config.BUFFER_SIZE];
		}
	}

	public void alertDuper(final String name) {
		PlayerHandler.messageToAll = "@red@Duper Detected.";
	}

	/**
	 * Shakes the player's screen. Parameters 1, 0, 0, 0 to reset.
	 * 
	 * @param verticleAmount
	 *            How far the up and down shaking goes (1-4).
	 * @param verticleSpeed
	 *            How fast the up and down shaking is.
	 * @param horizontalAmount
	 *            How far the left-right tilting goes.
	 * @param horizontalSpeed
	 *            How fast the right-left tiling goes..
	 */

	public void shakeScreen(int verticleAmount, int verticleSpeed,
			int horizontalAmount, int horizontalSpeed) {
		outStream.createFrame(35); // Creates frame 35.
		outStream.writeByte(verticleAmount);
		outStream.writeByte(verticleSpeed);
		outStream.writeByte(horizontalAmount);
		outStream.writeByte(horizontalSpeed);
	}

	/**
	 * Resets the shaking of the player's screen.
	 */
	public void resetShaking() {
		shakeScreen(0, 0, 0, 0);
	}

	public void flushOutStream() {
		if (disconnected || outStream.currentOffset == 0)
			return;
		synchronized (this) {
			StaticPacketBuilder out = new StaticPacketBuilder().setBare(true);
			byte[] temp = new byte[outStream.currentOffset];
			System.arraycopy(outStream.buffer, 0, temp, 0, temp.length);
			out.addBytes(temp);
			session.write(out.toPacket());
			outStream.currentOffset = 0;
		}
	}

	public Fishing getFishing() {
		return fish;
	}

	public void TanningInterface() {
		getPA().showInterface(14670);
		getPA().sendQuest("Leather", 14777);
		getPA().sendQuest("1gp", 14785);
		getPA().sendQuest("Hard Leather", 14781);
		getPA().sendQuest("5gp", 14789);
		getPA().sendFrame246(14769, 250, 1741);
		getPA().sendFrame246(14773, 250, 1743);
		getPA().sendFrame246(14771, 250, 1753);
		getPA().sendFrame246(14772, 250, 1751);
		getPA().sendFrame246(14775, 250, 1749);
		getPA().sendFrame246(14776, 250, 1747);
		getPA().sendQuest("", 14778);
		getPA().sendQuest("", 14786);
		getPA().sendQuest("", 14782);
		getPA().sendQuest("", 14790);
		int[] Line = { 14779, 14787, 14783, 14791, 14780, 14788, 14784, 14792 };
		String[] HideColor = { "Green", "Red", "Blue", "Black" };
		String[] HideCost = { "Free", "Free", "Free", "Free" };
		int HC = 0, i2 = 0;
		for (int i = 0; i < Line.length; i++) {
			if (HC == 0) {
				getPA().sendQuest(HideColor[(int) (i / 2)], Line[i]);
				HC = 1;
			} else {
				getPA().sendQuest(HideCost[(int) (i / 2)], Line[i]);
				HC = 0;
			}
		}
	}

	public boolean hasStaffOrRunes(final int staffId, final int runeId,
			final int runeAmnt) {
		return this.getItems().playerHasItem(staffId)
				|| getItems().playerHasItem(runeId, runeAmnt);
	}

	public void tannerX(int AmountToDo, int ItemGained, int DeletedItem,
			int MoneyLoss) {
		if (playerLevel[12] >= 0) {
			for (int X = 0; X < AmountToDo; X++) {
				if (getItems().playerHasItem(DeletedItem, 1)) {
					getItems().deleteItem(DeletedItem,
							getItems().getItemSlot(DeletedItem), 1);
					getItems().deleteItem(MoneyLoss,
							getItems().getItemSlot(MoneyLoss), 1);
					getItems().addItem(ItemGained, 1);
					sendMessage("The tanner tan's your hides for free!");
					getPA().closeAllWindows();
				} else {
					sendMessage("You need "
							+ getItems().getItemName(DeletedItem)
							+ " in order to tan "
							+ getItems().getItemName(ItemGained));
				}
			}
		}
	}

	public void sendClan(String name, String message, String clan, int rights) {
		outStream.createFrameVarSizeWord(217);
		outStream.writeString(name);
		outStream.writeString(message);
		outStream.writeString(clan);
		outStream.writeWord(rights);
		outStream.endFrameVarSize();
	}

	public static final int PACKET_SIZES[] = { 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, // 0
			0, 0, 0, 0, 8, 0, 6, 2, 2, 0, // 10
			0, 2, 0, 6, 0, 12, 0, 0, 0, 0, // 20
			0, 0, 0, 0, 0, 8, 4, 0, 0, 2, // 30
			2, 6, 0, 6, 0, -1, 0, 0, 0, 0, // 40
			0, 0, 0, 12, 0, 0, 0, 8, 8, 12, // 50
			8, 8, 0, 0, 0, 0, 0, 0, 0, 0, // 60
			6, 0, 2, 2, 8, 6, 0, -1, 0, 6, // 70
			0, 0, 0, 0, 0, 1, 4, 6, 0, 0, // 80
			0, 0, 0, 0, 0, 3, 0, 0, -1, 0, // 90
			0, 13, 0, -1, 0, 0, 0, 0, 0, 0,// 100
			0, 0, 0, 0, 0, 0, 0, 6, 0, 0, // 110
			1, 0, 6, 0, 0, 0, -1, 0, 2, 6, // 120
			0, 4, 6, 8, 0, 6, 0, 0, 0, 2, // 130
			0, 0, 0, 0, 0, 6, 0, 0, 0, 0, // 140
			0, 0, 1, 2, 0, 2, 6, 0, 0, 0, // 150
			0, 0, 0, 0, -1, -1, 0, 0, 0, 0,// 160
			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 170
			0, 8, 0, 3, 0, 2, 0, 0, 8, 1, // 180
			0, 0, 12, 0, 0, 0, 0, 0, 0, 0, // 190
			2, 0, 0, 0, 0, 0, 0, 0, 4, 0, // 200
			4, 0, 0, 0, 7, 8, 0, 0, 10, 0, // 210
			0, 0, 0, 0, 0, 0, -1, 0, 6, 0, // 220
			1, 0, 0, 0, 6, 0, 6, 8, 1, 0, // 230
			0, 4, 0, 0, 0, 0, -1, 0, -1, 4,// 240
			0, 0, 6, 6, 0, 0, 0 // 250
	};

	public void destruct() {
		if (session == null)
			return;

		if (inPits)
			Server.fightPits.removePlayerFromPits(playerId);
		if (clanId >= 0)
			Server.clanChat.leaveClan(playerId, clanId);
		Misc.println("[OFFLINE]: " + Misc.capitalize(playerName) + "");
		CycleEventHandler.getSingleton().stopEvents(this);
		HostList.getHostList().remove(session);
		disconnected = true;
		session.close();
		session = null;
		inStream = null;
		outStream = null;
		isActive = false;
		buffer = null;
		super.destruct();
	}

	public void sendMessage(String s) {
		// synchronized (this) {
		if (getOutStream() != null) {
			outStream.createFrameVarSize(253);
			outStream.writeString(s);
			outStream.endFrameVarSize();
		}

	}

	public void setSidebarInterface(int menuId, int form) {
		// synchronized (this) {
		if (getOutStream() != null) {
			outStream.createFrame(71);
			outStream.writeWord(form);
			outStream.writeByteA(menuId);
		}

	}

	public void initialize() {
		// synchronized (this)
		// welcomeScreenInterface();
		// getPA().loadQuests();
		outStream.createFrame(249);
		outStream.writeByteA(1); // 1 for members, zero for free
		outStream.writeWordBigEndianA(playerId);
		for (int j = 0; j < Server.playerHandler.players.length; j++) {
			if (j == playerId)
				continue;
			if (Server.playerHandler.players[j] != null) {
				if (Server.playerHandler.players[j].playerName
						.equalsIgnoreCase(playerName))
					disconnected = true;
			}
		}
		// getPA().setSidebarInterfaces(this);
		// if(showWelcomeScreen){
		// getPA().showInterface(15244);
		// }
		for (int i = 0; i < 25; i++) {
			getPA().setSkillLevel(i, playerLevel[i], playerXP[i]);
			getPA().refreshSkill(i);
		}
		for (int p = 0; p < PRAYER.length; p++) { // reset prayer glows
			prayerActive[p] = false;
			getPA().sendFrame36(PRAYER_GLOW[p], 0);
		}
		getPA().handleWeaponStyle();
		getPA().handleLoginText();
		accountFlagged = getPA().checkForFlags();
		// getPA().sendFrame36(43, fightMode-1);
		getPA().sendFrame36(108, 0);// resets autocast button
		getPA().sendFrame36(172, 1);
		getPA().sendFrame107(); // reset screen
		getPA().setChatOptions(0, 0, 0); // reset private messaging options
		setSidebarInterface(1, 3917);
		setSidebarInterface(2, 638);
		setSidebarInterface(3, 3213);
		setSidebarInterface(4, 1644);
		setSidebarInterface(5, 5608);
		if (playerMagicBook == 0) {
			setSidebarInterface(6, 1151); // modern
		} else {
			setSidebarInterface(6, 12855); // ancient
		}
		correctCoordinates();
		setSidebarInterface(7, 18128);
		setSidebarInterface(8, 5065);
		setSidebarInterface(9, 5715);
		setSidebarInterface(10, 2449);
		// setSidebarInterface(11, 4445); // wrench tab
		setSidebarInterface(11, 904); // wrench tab
		setSidebarInterface(12, 147); // run tab
		setSidebarInterface(13, -1);
		setSidebarInterface(0, 2423);
		getPA().loadQuests();
		sendMessage("Welcome to " + Config.SERVER_NAME + ".");
		/*
		 * if(!membership) { sendMessage("You are currently not a member."); }
		 * else {
		 * sendMessage("You are currently a member. Membership never expires.");
		 * }
		 */
		getPA().showOption(4, 0, "Follow", 4);
		getPA().showOption(5, 0, "Trade With", 3);
		getItems().resetItems(3214);
		getItems().sendWeapon(playerEquipment[playerWeapon],
				getItems().getItemName(playerEquipment[playerWeapon]));
		getItems().resetBonus();
		getItems().getBonus();
		getItems().writeBonus();
		getItems().setEquipment(playerEquipment[playerHat], 1, playerHat);
		getItems().setEquipment(playerEquipment[playerCape], 1, playerCape);
		getItems().setEquipment(playerEquipment[playerAmulet], 1, playerAmulet);
		getItems().setEquipment(playerEquipment[playerArrows],
				playerEquipmentN[playerArrows], playerArrows);
		getItems().setEquipment(playerEquipment[playerChest], 1, playerChest);
		getItems().setEquipment(playerEquipment[playerShield], 1, playerShield);
		getItems().setEquipment(playerEquipment[playerLegs], 1, playerLegs);
		getItems().setEquipment(playerEquipment[playerHands], 1, playerHands);
		getItems().setEquipment(playerEquipment[playerFeet], 1, playerFeet);
		getItems().setEquipment(playerEquipment[playerRing], 1, playerRing);
		getItems().setEquipment(playerEquipment[playerWeapon],
				playerEquipmentN[playerWeapon], playerWeapon);
		getCombat().getPlayerAnimIndex(
				getItems().getItemName(playerEquipment[playerWeapon])
						.toLowerCase());
		getPA().logIntoPM();
		getItems().addSpecialBar(playerEquipment[playerWeapon]);
		saveTimer = Config.SAVE_TIMER;
		saveCharacter = true;
		Misc.println("[ONLINE]: " + Misc.capitalize(playerName) + "");
		handler.updatePlayer(this, outStream);
		handler.updateNPC(this, outStream);
		flushOutStream();
		getPA().clearClanChat();
		getPA().resetFollow();
		if (addStarter) {
			getPA().addStarter();
			eco_reset = Config.ECO_RESET;
			getPA().showInterface(3559);
			canChangeAppearance = true;
		}
		if (eco_reset < Config.ECO_RESET) {
			for (int i = 0; i < 25; i++) {
				if (playerLevel[i] <= 79) {
					if (i == 3) {
						playerLevel[i] = 10;
						playerXP[i] = 1355;
					} else {
						playerLevel[i] = 1;
						playerXP[i] = 0;
					}
					getPA().setSkillLevel(i, playerLevel[i], playerXP[i]);
				} else {
					if (i == 3) {
						playerLevel[i] = 10;
						playerXP[i] = 1355;
					} else {
						playerLevel[i] = 1;
						playerXP[i] = 0;
					}
					getPA().setSkillLevel(i, playerLevel[i], playerXP[i]);
				}
				getPA().refreshSkill(i);
			}
			if (eco_reset != 3) {
				getItems().deleteAllItems();
				getItems().deleteEquipment();
				for (int i = 0; i < bankItems.length; i++) {
					bankItems[i] = -1;
					bankItemsN[i] = 0;
				}
				if (!addStarter) {
					getItems().addItem(995, 250000);
				}
			}
			sendMessage("@red@ [SKILL AND ECO RESET]");
			eco_reset = Config.ECO_RESET;
			PlayerSave.saveGame(this);
		}
		if (autoRet == 1)
			getPA().sendFrame36(172, 1);
		else
			getPA().sendFrame36(172, 0);
		totalLevel = getPA().totalLevel();
		xpTotal = getPA().xpTotal();
		playerSkills();
		// dupeDefender.loginDuperCheck();
	}

	public void cancelPlayerSkills() {
		for (final PlayerSkill skill : playerSkills) {
			if (skill == null)
				continue;
			if (skill.isActive())
				skill.kill();
		}
	}

	public void playerSkills() {
		playerSkills.add(mine);
		playerSkills.add(fisha);
	}

	public void update() {
		// synchronized (this) {
		handler.updatePlayer(this, outStream);
		handler.updateNPC(this, outStream);
		flushOutStream();

	}

	public void logout() {
		// synchronized (this) {
		if (System.currentTimeMillis() - logoutDelay > 10000) {
			outStream.createFrame(109);
			CycleEventHandler.getSingleton().stopEvents(this);
			properLogout = true;
			if (playerRights < 2 && !playerName.equalsIgnoreCase("mod tanner")
					&& !playerName.equalsIgnoreCase("oo legit oo")) {
				SQL.createConnection();
				if (SQL.saveHighScore(this))
					SQL.destroyConnection();
			}
		} else {
			sendMessage("You must wait a few seconds from being out of combat to logout.");
		}

	}

	public int packetSize = 0, packetType = -1;

	public int totalPlaytime() {
		return (pTime / 2);
	}

	public String getPlaytime() {
		int DAY = (totalPlaytime() / 86400);
		int HR = (totalPlaytime() / 3600) - (DAY * 24);
		int MIN = (totalPlaytime() / 60) - (DAY * 1440) - (HR * 60);
		return (DAY + " days " + HR + " hours " + MIN + " minutes");
	}

	public String getSmallPlaytime() {
		int DAY = (totalPlaytime() / 86400);
		int HR = (totalPlaytime() / 3600) - (DAY * 24);
		int MIN = (totalPlaytime() / 60) - (DAY * 1440) - (HR * 60);
		return ("Day:" + DAY + "/Hr:" + HR + "/Min:" + MIN + "");
	}

	public void process() {
		// getPA().sendFrame126("Combat Level: "+combatLevel+"", 19999);
		getPA().sendFrame126("Combat Level: " + combatLevel + "", 3983);
		antiBot.process();
		if (yellTimer > 0) {
			yellTimer--;
		} else if (yellTimer == 0) {
			yellTimer = -1;
		}
		if (!hasRandom) {
			for (final RandomEvent random : randoms) {
				if (random == null)
					continue;
				random.initRandom();
			}
		}
		/**
		 * Process Skills.
		 */
		if (mineEss.isActive())
			mineEss.process();
		woodcutting.processWC();
		firemaking.processFires();
		if (smeltTimer > 0 && smeltType > 0) {
			smeltTimer--;
		} else if (smeltTimer == 0 && smeltType > 0) {
			getSmithing().smelt(smeltType);
		}
		if (!isResting) {
			if (playerEnergy < 100
					&& System.currentTimeMillis() - lastIncrease >= getPA()
							.raiseTimer()) {
				playerEnergy += Misc.random(3);
				lastIncrease = System.currentTimeMillis();
			}
		}
		/*
		 * if (isResting) { if (playerEnergy < 100 && System.currentTimeMillis()
		 * - lastIncrease >= getPA() .raiseTimer2()) { playerEnergy += 1;
		 * lastIncrease = System.currentTimeMillis(); } }
		 */
		getPA().writeEnergy();
		if (System.currentTimeMillis() - specDelay > Config.INCREASE_SPECIAL_AMOUNT) {
			specDelay = System.currentTimeMillis();
			if (specAmount < 10) {
				specAmount += .5;
				if (specAmount > 10)
					specAmount = 10;
				getItems().addSpecialBar(playerEquipment[playerWeapon]);
			}
		}

		if (followId > 0) {
			getPA().followPlayer();
		} else if (followId2 > 0) {
			getPA().followNpc();
		}
		getFishing().FishingProcess();
		getCombat().handlePrayerDrain();
		if (System.currentTimeMillis() - singleCombatDelay > 3300) {
			underAttackBy = 0;
		}
		if (System.currentTimeMillis() - singleCombatDelay2 > 3300) {
			underAttackBy2 = 0;
		}

		if (System.currentTimeMillis() - restoreStatsDelay > 60000) {
			restoreStatsDelay = System.currentTimeMillis();
			for (int level = 0; level < playerLevel.length; level++) {
				if (playerLevel[level] < getLevelForXP(playerXP[level])) {
					if (level != 5) { // prayer doesn't restore
						playerLevel[level] += 1;
						getPA().setSkillLevel(level, playerLevel[level],
								playerXP[level]);
						getPA().refreshSkill(level);
					}
				} else if (playerLevel[level] > getLevelForXP(playerXP[level])) {
					playerLevel[level] -= 1;
					getPA().setSkillLevel(level, playerLevel[level],
							playerXP[level]);
					getPA().refreshSkill(level);
				}
			}
		}

		if (inWild()) {
			int modY = absY > 6400 ? absY - 6400 : absY;
			wildLevel = (((modY - 3520) / 8) + 1);
			getPA().walkableInterface(197);
			if (Config.SINGLE_AND_MULTI_ZONES) {
				if (inMulti()) {
					getPA().sendFrame126("@yel@Level: " + wildLevel, 199);
				} else {
					getPA().sendFrame126("@yel@Level: " + wildLevel, 199);
				}
			} else {
				getPA().multiWay(-1);
				getPA().sendFrame126("@yel@Level: " + wildLevel, 199);
			}
			getPA().showOption(3, 0, "Attack", 1);
		} else if (inDuelArena()) {
			getPA().walkableInterface(201);
			if (duelStatus == 5) {
				getPA().showOption(3, 0, "Attack", 1);
			} else {
				getPA().showOption(3, 0, "Challenge", 1);
			}
		} else if (inBarrows()) {
			getPA().sendFrame99(2);
			getPA().sendFrame126("Kill Count: " + barrowsKillCount, 4536);
			getPA().walkableInterface(4535);
		} else if (inCwGame || inPits) {
			getPA().showOption(3, 0, "Attack", 1);
		} else if (getPA().inPitsWait()) {
			getPA().showOption(3, 0, "Null", 1);
		} else if (!inCwWait) {
			getPA().sendFrame99(0);
			getPA().walkableInterface(-1);
			getPA().showOption(3, 0, "Null", 1);
		}

		if (!hasMultiSign && inMulti()) {
			hasMultiSign = true;
			getPA().multiWay(1);
		}

		if (hasMultiSign && !inMulti()) {
			hasMultiSign = false;
			getPA().multiWay(-1);
		}

		if (skullTimer > 0) {
			skullTimer--;
			if (skullTimer == 1) {
				isSkulled = false;
				attackedPlayers.clear();
				headIconPk = -1;
				skullTimer = -1;
				getPA().requestUpdates();
			}
		}

		if (isDead && respawnTimer == -6) {
			getPA().applyDead();
		}

		if (respawnTimer == 7) {
			respawnTimer = -6;
			getPA().giveLife();
		} else if (respawnTimer == 12) {
			respawnTimer--;
			startAnimation(0x900);
			poisonDamage = -1;
		}

		if (respawnTimer > -6) {
			respawnTimer--;
		}
		if (freezeTimer > -6) {
			freezeTimer--;
			if (frozenBy > 0) {
				if (Server.playerHandler.players[frozenBy] == null) {
					freezeTimer = -1;
					frozenBy = -1;
				} else if (!goodDistance(absX, absY,
						Server.playerHandler.players[frozenBy].absX,
						Server.playerHandler.players[frozenBy].absY, 20)) {
					freezeTimer = -1;
					frozenBy = -1;
				}
			}
		}

		if (hitDelay > 0) {
			hitDelay--;
		}
		if (pTime != 2147000000) {
			pTime++;
		}
		if (teleTimer > 0) {
			teleTimer--;
			if (!isDead) {
				if (teleTimer == 1 && newLocation > 0) {
					teleTimer = 0;
					getPA().changeLocation();
				}
				if (teleTimer == 5) {
					teleTimer--;
					getPA().processTeleport();
				}
				if (teleTimer == 9 && teleGfx > 0) {
					teleTimer--;
					gfx100(teleGfx);
				}
			} else {
				teleTimer = 0;
			}
		}

		if (hitDelay == 1) {
			if (oldNpcIndex > 0) {
				getCombat().delayedHit(oldNpcIndex);
			}
			if (oldPlayerIndex > 0) {
				getCombat().playerDelayedHit(oldPlayerIndex);
			}
		}

		if (attackTimer > 0) {
			attackTimer--;
		}

		if (attackTimer == 1) {
			if (npcIndex > 0 && clickNpcType == 0) {
				getCombat().attackNpc(npcIndex);
			}
			if (playerIndex > 0) {
				getCombat().attackPlayer(playerIndex);
			}
		} else if (attackTimer <= 0 && (npcIndex > 0 || playerIndex > 0)) {
			if (npcIndex > 0) {
				attackTimer = 0;
				getCombat().attackNpc(npcIndex);
			} else if (playerIndex > 0) {
				attackTimer = 0;
				getCombat().attackPlayer(playerIndex);
			}
		}

		if (timeOutCounter > Config.TIMEOUT) {
			disconnected = true;
		}

		timeOutCounter++;

		if (inTrade && tradeResetNeeded) {
			Client o = (Client) Server.playerHandler.players[tradeWith];
			if (o != null) {
				if (o.tradeResetNeeded) {
					getTradeAndDuel().resetTrade();
					o.getTradeAndDuel().resetTrade();
				}
			}
		}
	}

	public void setCurrentTask(Future<?> task) {
		currentTask = task;
	}

	public Future<?> getCurrentTask() {
		return currentTask;
	}

	public synchronized Stream getInStream() {
		return inStream;
	}

	public synchronized int getPacketType() {
		return packetType;
	}

	public synchronized int getPacketSize() {
		return packetSize;
	}

	public synchronized Stream getOutStream() {
		return outStream;
	}

	public ItemAssistant getItems() {
		return itemAssistant;
	}

	public PlayerAssistant getPA() {
		return playerAssistant;
	}

	public DialogueHandler getDH() {
		return dialogueHandler;
	}

	public ShopAssistant getShops() {
		return shopAssistant;
	}

	public TradeAndDuel getTradeAndDuel() {
		return tradeAndDuel;
	}

	public CombatAssistant getCombat() {
		return combatAssistant;
	}

	public ActionHandler getActions() {
		return actionHandler;
	}

	public PlayerKilling getKill() {
		return playerKilling;
	}

	public IoSession getSession() {
		return session;
	}

	public Potions getPotions() {
		return potions;
	}

	public PotionMixing getPotMixing() {
		return potionMixing;
	}

	public Food getFood() {
		return food;
	}

	private boolean isBusy = false;
	private boolean isBusyHP = false;
	public boolean isBusyFollow = false;

	public boolean checkBusy() {
		/*
		 * if (getCombat().isFighting()) { return true; }
		 */
		if (isBusy) {
			// actionAssistant.sendMessage("You are too busy to do that.");
		}
		return isBusy;
	}

	public boolean checkBusyHP() {
		return isBusyHP;
	}

	public boolean checkBusyFollow() {
		return isBusyFollow;
	}

	public void setBusy(boolean isBusy) {
		this.isBusy = isBusy;
	}

	public boolean isBusy() {
		return isBusy;
	}

	public void setBusyFollow(boolean isBusyFollow) {
		this.isBusyFollow = isBusyFollow;
	}

	public void setBusyHP(boolean isBusyHP) {
		this.isBusyHP = isBusyHP;
	}

	public boolean isBusyHP() {
		return isBusyHP;
	}

	public boolean isBusyFollow() {
		return isBusyFollow;
	}

	private boolean canWalk = true;

	public boolean canWalk() {
		return canWalk;
	}

	public void setCanWalk(boolean canWalk) {
		this.canWalk = canWalk;
	}

	public PlayerAssistant getPlayerAssistant() {
		return playerAssistant;
	}

	public ActionAssistant2 getAA2() {
		return actionAssistant2;
	}

	public SkillInterfaces getSI() {
		return skillInterfaces;
	}

	/**
	 * Skill Constructors
	 */
	public Slayer getSlayer() {
		return slayer;
	}

	public Runecrafting getRunecrafting() {
		return runecrafting;
	}

	/*
	 * public Cooking getCooking() { return cooking; }
	 */

	public Agility getAgil() {
		return agility;
	}

	public Crafting getCrafting() {
		return crafting;
	}

	public SmithingInterface getSmithingInt() {
		return smithInt;
	}

	public Smithing getSmithing() {
		return smith;
	}

	public Farming getFarming() {
		return farming;
	}

	public Herblore getHerblore() {
		return herblore;
	}

	/*
	 * public Fletching getFletching() { return fletching; }
	 */

	public Magic getMagic() {
		return magic;
	}

	public Prayer getPrayer() {
		return prayer;
	}

	/**
	 * End of Skill Constructors
	 */

	public void queueMessage(Packet arg1) {
		synchronized (queuedPackets) {
			// if (arg1.getId() != 41)
			queuedPackets.add(arg1);
			// else
			// processPacket(arg1);
		}
	}

	public synchronized boolean processQueuedPackets() {
		Packet p = null;
		synchronized (queuedPackets) {
			p = queuedPackets.poll();
		}
		if (p == null) {
			return false;
		}
		inStream.currentOffset = 0;
		packetType = p.getId();
		packetSize = p.getLength();
		inStream.buffer = p.getData();
		if (packetType > 0) {
			// sendMessage("PacketType: " + packetType);
			PacketHandler.processPacket(this, packetType, packetSize);
		}
		timeOutCounter = 0;
		return true;
	}

	public synchronized boolean processPacket(Packet p) {
		synchronized (this) {
			if (p == null) {
				return false;
			}
			inStream.currentOffset = 0;
			packetType = p.getId();
			packetSize = p.getLength();
			inStream.buffer = p.getData();
			if (packetType > 0) {
				// sendMessage("PacketType: " + packetType);
				PacketHandler.processPacket(this, packetType, packetSize);
			}
			timeOutCounter = 0;
			return true;
		}
	}

	public void correctCoordinates() {
		if (inPcGame()) {
			getPA().movePlayer(2657, 2639, 0);
		}
		if (inFightCaves()) {
			getPA().movePlayer(absX, absY, playerId * 4);
			sendMessage("Your wave will start in 10 seconds.");
			EventManager.getSingleton().addEvent(new Event() {
				public void execute(EventContainer c) {
					Server.fightCaves.spawnNextWave((Client) Server.playerHandler.players[playerId]);
					c.stop();
				}
			}, 10000);

		}

	}

}
